package com.boot2.core.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
* @author zhangweilin
* @date 2018/9/15 21:22
* @description:
*/
public class PayDigestUtil {
   protected static Log log = LogFactory.getLog(PayDigestUtil.class);
   private static String encodingCharset = "UTF-8";

   /**
    * @param aValue
    * @param aKey
    * @return
    */
   public static String hmacSign(String aValue, String aKey) {
       byte kipad[] = new byte[64];
       byte kopad[] = new byte[64];
       byte keyb[];
       byte value[];
       try {
           keyb = aKey.getBytes(encodingCharset);
           value = aValue.getBytes(encodingCharset);
       } catch (UnsupportedEncodingException e) {
           keyb = aKey.getBytes();
           value = aValue.getBytes();
       }

       Arrays.fill(kipad, keyb.length, 64, (byte) 54);
       Arrays.fill(kopad, keyb.length, 64, (byte) 92);
       for (int i = 0; i < keyb.length; i++) {
           kipad[i] = (byte) (keyb[i] ^ 0x36);
           kopad[i] = (byte) (keyb[i] ^ 0x5c);
       }

       MessageDigest md = null;
       try {
           md = MessageDigest.getInstance("MD5");
       } catch (NoSuchAlgorithmException e) {

           return null;
       }
       md.update(kipad);
       md.update(value);
       byte dg[] = md.digest();
       md.reset();
       md.update(kopad);
       md.update(dg, 0, 16);
       dg = md.digest();
       return toHex(dg);
   }

   public static String toHex(byte input[]) {
       if (input == null) {
           return null;
       }
       StringBuffer output = new StringBuffer(input.length * 2);
       for (int i = 0; i < input.length; i++) {
           int current = input[i] & 0xff;
           if (current < 16) {
               output.append("0");
           }
           output.append(Integer.toString(current, 16));
       }

       return output.toString();
   }


    /**
     * md5 加密操作
     * @param value
     * @param charset
     * @return
     */
   public static String md5(String value, String charset) {
       MessageDigest md = null;
       try {
           byte[] data = value.getBytes(charset);
           md = MessageDigest.getInstance("MD5");
           byte[] digestData = md.digest(data);
           return toHex(digestData);
       } catch (NoSuchAlgorithmException e) {
           e.printStackTrace();
           return null;
       } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
           return null;
       }
   }

    /**
     * 给Object类型请求参数加密
     * @param o
     * @param key
     * @return
     * @throws IllegalAccessException
     */
   public static String getSign(Object o, String key) throws IllegalAccessException {
       if(o instanceof Map) {
           return getSign((Map<String, Object>)o, key);
       }
       ArrayList<String> list = new ArrayList<String>();
       Class cls = o.getClass();
       Field[] fields = cls.getDeclaredFields();
       for (Field f : fields) {
           f.setAccessible(true);
           if (f.get(o) != null && !"".equals(f.get(o))) {
               list.add(f.getName() + "=" + f.get(o) + "&");
           }
       }
       int size = list.size();
       String [] arrayToSort = list.toArray(new String[size]);
       Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
       StringBuilder sb = new StringBuilder();
       for(int i = 0; i < size; i ++) {
           sb.append(arrayToSort[i]);
       }
       String result = sb.toString();
       result += "key=" + key;
       log.info("Object类型参数 md5加密前字符串:" + result);
       result = md5(result, encodingCharset).toUpperCase();
       log.info("Object类型参数 md5加密结果:" + result);
       return result;
   }

    /**
     * 给map类型请求参数加密
     * @param map
     * @param key
     * @return
     */
   public static String getSign(Map<String,Object> map, String key){
       ArrayList<String> list = new ArrayList<String>();
       for(Map.Entry<String,Object> entry:map.entrySet()){
           if(!"".equals(entry.getValue()) && null != entry.getValue()){
               list.add(entry.getKey() + "=" + entry.getValue() + "&");
           }
       }
       int size = list.size();
       String [] arrayToSort = list.toArray(new String[size]);
       Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
       StringBuilder sb = new StringBuilder();
       for(int i = 0; i < size; i ++) {
           sb.append(arrayToSort[i]);
       }
       String result = sb.toString();
       result += "key=" + key;
       log.info("map类型参数 md5加密前字符串:" + result);
       result = md5(result, encodingCharset).toUpperCase();
       log.info("map类型参数 md5加密结果:" + result);
       return result;
   }

   /**
    *给map类型请求参数加密
    * @param map
    * @param key
    * @param notContains 不包含的签名字段
    * @return
    */
   public static String getSign(Map<String,Object> map, String key, String... notContains){
       Map<String,Object> newMap = new HashMap<String,Object>();
       for(Map.Entry<String,Object> entry:map.entrySet()){
           boolean isContain = false;
           for(int i=0; i<notContains.length; i++) {
               if(entry.getKey().equals(notContains[i])) {
                   isContain = true;
                   break;
               }
           }
           if(!isContain) {
               newMap.put(entry.getKey(), entry.getValue());
           }
       }
       return getSign(newMap, key);
   }

   public static void main(String[] args) {
       String key = "8UPp0KE8sq73zVP370vko7C39403rtK1YwX40Td6irH216036H27Eb12792t";
       String dataStr = "AnnulCard1000043252120080620160450.0http://localhost/SZXpro/callback.asp这4564868265473632445648682654736324511";
       System.out.println(hmacSign(dataStr, key));

       System.out.println(md5(dataStr, "UTF-8"));
       System.out.println(md5(dataStr, "GBK"));
   }
}
